from datetime import datetime
from typing import Optional
from settings import Settings
from ym import YandexMusic, Queue

from pypresence import Presence

from timing import Timing, DEFAULT_TIMEZONE
import time


class Rpc:
    """
    Класс для работы с Discord RPC
    """

    # Discord RPC API
    presence: Presence

    # Главные объекты
    settings: Settings
    ym: YandexMusic

    # Настройки очереди
    queues_type = {
        # Страница артиста 
        'artist': {
            'track': True,
            'probably_non_music': False,
            'image_cover': True
        },
        # Другие
        'various': {
            'track': True,
            'probably_non_music': False,
            'image_cover': True
        },
        # Плейлист
        # Нельзя получить текущий трек
        'playlist': {
            'track': False,
            'playlist': True,
            'favorite_playlist': True,
            'probably_non_music': False,
            'image_cover': True
        },
        # Поток
        # Нельзя получить текущий трек
        'radio': {
            'track': False,
            'playlist': False,
            'radio': True,
            'probably_non_music': False,
            'image_cover': True
        },
        # Поиск
        'search': {
            'track': True,
            'image_cover': True,
            'probably_non_music': False
        },
        # Альбом
        # Возможно может быть книгой или подкастом
        'album': {
            'track': True,
            'probably_non_music': True,
            'image_cover': True
        }
    }

    def __init__(self, settings: Settings, ym: YandexMusic) -> None:
        """
        Инициализировать класс

        Args:
            settings (Settings): Настройки
            ym (YandexMusic): Класс Яндекс.Музыки

        Raises:
            Exception: Не могу подключиться к Дискорду.
        """

        # Ставим главные объекты
        self.settings = settings
        self.ym = ym

        # Число попыток
        max_times = 10

        for times in range(max_times):
            try:
                # Попытка соединения к клиенту Discord
                self.presence = Presence(self.settings.client_id)
                self.presence.connect()

                return
            except:
                pass

        raise Exception('Не могу подключиться к Дискорду.')

    def get_timing(self, queue: Queue) -> float:
        """
        Получение тиминга

        Args:
            queue (Queue): Текущая очередь

        Returns:
            float: Тиминг
        """

        # Если у типа нету настроек
        if queue.context.type not in self.queues_type:
            return None

        # Получение настроек
        queue_config = self.queues_type[queue.context.type]

        # Если можно получить трек
        if queue_config['track']:
            # Получение трек
            current_track = self.ym.get_current_track_from_activity(
                queue=queue)
            # Получение длительность трека в секундах
            return Timing.milli_to_secs(current_track.duration_ms)

        # Если можно получить плейлист
        # TODO: Сделать по нормальному
        if queue_config['playlist']:
            # Получение плейлист
            current_playlist = self.ym.get_playlist(queue.context.id)

            # Тиминг
            timing_result = 0
            # Время сначало даты последнего изменения
            offset = datetime.now(tz=DEFAULT_TIMEZONE).timestamp(
            ) - Timing.get_epoch(queue.modified)

            # Цикл с треками
            for short_track in current_playlist.tracks:
                # Получение полных данных о треке
                track = short_track.fetch_track()

                # Получение длительность трека в секундах
                duration = Timing.milli_to_secs(track.duration_ms)
                timing_result = duration

                # Отнимаем длину от времени
                offset -= duration

                # Если время менее 1, то останавливаем цикл
                if offset < 1:
                    break

            # Возращаем результат
            return timing_result

        # Возращаем стандартное число
        return 360

    def update_rpc(self, queue: Queue) -> None:
        """
        Обновление статуса в Дискорде

        Args:
            queue (Queue): Текущая очередь
        """

        # Если у типа нету настроек
        if queue.context.type not in self.queues_type:
            return None

        # Получение настроек
        queue_config = self.queues_type[queue.context.type]

        # Если можно получить трек
        if queue_config['track']:
            # Получение трека
            current_track = self.ym.get_current_track_from_activity(queue)

            large_image = None
            small_image = self.settings.ym_icon

            # Если можно получить обложку
            if queue_config['image_cover']:
                # Ставим обложку
                large_image = f"https://{current_track.og_image.replace('%%', '200x200')}"

            # Если артистов нету
            if len(current_track.artists_name()) == 0:
                artists = queue.context.description
            # Если есть артисты
            elif len(current_track.artists_name()) >= 1:
                artists = ', '.join(current_track.artists_name())

            # Если может быть книгой или подкастом и артистов нету
            # То 100% это не музыка
            if queue_config['probably_non_music'] and len(current_track.artists_name()) == 0: 
                word = 'подкаст/книгу'
            else: 
                word = 'трек'

            # Тупой решение, но рабочие
            # Если бы не & от Tally Hall, то я бы это не сделал бы
            details = current_track.title
            if len(details) < 2:
                details += "  "

            # Обновление статуса в Дискорде
            self.presence.update(
                state=artists,
                details=details,
                large_image=large_image,
                small_image=small_image,
                buttons=[{
                    'label': f'Ссылка на {word}',
                    'url': f'https://music.yandex.ru/album/{current_track.albums[0].id}/track/{current_track.id}'
                }]
            )
            return

        # Если можно получить плейлист
        if queue_config['playlist']:
            # Получение плейлиста
            current_playlist = self.ym.get_playlist(queue.context.id)

            large_image = None
            small_image = self.settings.ym_icon

            # Если можно получить обложку
            if queue_config['image_cover']:
                # Ставим обложку
                large_image = f"https://{current_playlist.og_image.replace('%%', '200x200')}"

                # Если плейлист это "Мне нравится"
                if current_playlist.playlist_id.endswith(":3"):
                    # Ставим обложку от Мне нравится
                    large_image = "https://music.yandex.ru/blocks/playlist-cover/playlist-cover_like.png"

            buttons = [{
                'label': 'Ссылка на плейлист',
                'url': f'https://music.yandex.ru/users/{current_playlist.owner.login}/playlists/{current_playlist.playlist_id.split(":")[1]}'
            }]
            title = current_playlist.title

            # Если плейлист это "Мне нравится"
            if current_playlist.playlist_id.endswith(":3"):
                title = "Мне нравится"
                buttons = None

            # Обновление статуса в Дискорде
            self.presence.update(
                state='Слушаем плейлист',
                details=title,
                large_image=large_image,
                small_image=small_image,
                buttons=buttons
            )
            return

        # Если можно получить поток
        if queue_config['radio']:
            # Получение потока
            current_radio = self.ym.get_radio(queue.context.id)

            # Если не можем получить поток (Моя волна)
            if not current_radio:
                # Обновление статуса в Дискорде c простыми данными
                self.presence.update(
                    state='Слушает поток',
                    details=queue.context.description,
                    large_image=self.settings.ym_icon
                )
                return

            large_image = None
            small_image = self.settings.ym_icon

            # Если можно получить иконку/обложку
            if queue_config['image_cover']:
                # Если есть иконка
                if current_radio.full_image_url:
                    # Ставим иконку
                    large_image = f"https://{current_radio.full_image_url.replace('%%', '200x200')}"
                # Если нету
                else:
                    # То ставим обложку
                    large_image = f"https://{current_radio.mts_full_image_url.replace('%%', '200x200')}"

            # Обновление статуса в Дискорде
            self.presence.update(
                state='Слушает поток',
                details=current_track.title,
                large_image=large_image,
                small_image=small_image
            )
            return
        
        # Очистка статуса, если не можем изменить его
        self.presence.clear()

    def handle(self) -> None:
        """
        Обрабатывать данные с Яндекс Музыки и статус в Дискорде
        """

        while True:
            # Получение текущий очереди
            queue = self.ym.get_last_activity()

            # Получение тиминга
            timing = self.get_timing(queue=queue)
            # Время сначало даты последнего изменения
            offset = datetime.now(tz=DEFAULT_TIMEZONE).timestamp(
            ) - Timing.get_epoch(queue.modified)

            # Еcли тиминга больше чем время
            if offset < timing:
                # Обновление статуса в Дискорде
                self.update_rpc(queue)
            else:
                # Очистка статуса
                self.presence.clear()

            # Ждать >=5 секунд
            time.sleep(self.settings.update_time)
